﻿using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using XieCan.AspMVC.Entities;
using XieCan.AspMVC.IDAL;
using XieCan.AspMVC.Models;

namespace XieCan.AspMVC.DAL
{
    /// <summary>
    /// 公共的数据操作基类，封装了增删改查的基本操作
    /// </summary>
    /// <remarks>其他类只需要继承此类，便可拥有基本的增删改查的业务</remarks>
    /// <typeparam name="TModel">BaseModel及其所有子类类型</typeparam>
    public class BaseDAL<TModel> : XieCanBase, IBaseDAL<TModel>
        where TModel : BaseModel
    {
        /// <summary>
        /// 获取唯一数据上下文
        /// </summary>
        protected EntitiesContext Entities
        {
            get
            {

                //单例模式：保证线程实例唯一
                EntitiesContext entities = (EntitiesContext)CallContext.GetData("EntitiesContext");
                if (entities == null)
                {
                    entities = new EntitiesContext();

                    CallContext.SetData("EntitiesContext", entities);
                }
                return entities;
            }
        }

        public OperateResult<bool> Insert(params TModel[] models)
        {
            if (models == null || models.Count() < 1)
                return OperateResult<bool>.Failed("添加的实体不能为null");

            try
            {
                foreach (var model in models)
                {
                    Entities.Entry(model).State = EntityState.Added;
                }
                return OperateResult<bool>.Succeeded(Entities.SaveChanges() > 0);
            }
            catch (Exception ex)
            {
                return OperateResult<bool>.Failed(ex);
            }
        }

        public OperateResult<bool> Delete(params TModel[] models)
        {
            if (models == null || models.Count() < 1)
                return OperateResult<bool>.Failed("删除的实体不能为null");

            for (int i = 0; i < models.Length; i++)
            {
                models[i].IsDeleted = false;
            }

            return Update(models);
        }

        public OperateResult<bool> Update(params TModel[] models)
        {
            if (models == null || models.Count() < 1)
                return OperateResult<bool>.Failed("更新的实体不能为null");

            try
            {
                foreach (var model in models)
                {
                    Entities.Set<TModel>().Attach(model);
                    Entities.Entry(model).State = EntityState.Modified;
                }
                return OperateResult<bool>.Succeeded(Entities.SaveChanges() > 0);
            }
            catch (DbUpdateException ex)
            {
                ex.Entries.Single().Reload();
                return OperateResult<bool>.Failed(ex);
            }
            catch (Exception ex)
            {
                return OperateResult<bool>.Failed(ex);
            }
        }

        public OperateResult<IQueryable<TModel>> Select(Expression<Func<TModel, bool>> whereLambda)
        {
            try
            {
                var list = Entities.Set<TModel>().Where(whereLambda);
                return OperateResult<IQueryable<TModel>>.Succeeded(list);
            }
            catch (Exception ex)
            {
                return OperateResult<IQueryable<TModel>>.Failed(ex);
            }
        }

        public OperateResult<TModel> Model(Expression<Func<TModel, bool>> whereLambda)
        {
            try
            {
                var models = Entities.Set<TModel>().FirstOrDefault(whereLambda);
                return OperateResult<TModel>.Succeeded(models);
            }
            catch (Exception ex)
            {
                return OperateResult<TModel>.Failed(ex);
            }
        }

        public OperateResult<IQueryable<TModel>> Select<TKey>(Expression<Func<TModel, bool>> whereLambda, Expression<Func<TModel, TKey>> orderBy, bool isAsc)
        {
            var result = Select(whereLambda);
            if (result.State)
            {
                try
                {
                    var list = result.Data;
                    var query = list.OrderBy(orderBy);
                    if (!isAsc)
                    {
                        query = list.OrderByDescending(orderBy);
                    }
                    return OperateResult<IQueryable<TModel>>.Succeeded(query);
                }
                catch (Exception ex)
                {
                    return OperateResult<IQueryable<TModel>>.Failed(ex);
                }
            }
            return OperateResult<IQueryable<TModel>>.Failed(result.Error);
        }

        public OperateResult<IQueryable<TModel>> Select<TKey>(Expression<Func<TModel, bool>> whereLambda, Expression<Func<TModel, TKey>> orderBy, out int rowCount, bool isAsc, int pageIndex, int pageSize)
        {
            var result = Select(whereLambda, orderBy, isAsc);
            if (result.State)
            {
                var list = result.Data;

                //获取总记录数
                rowCount = list.Count();

                //边界值判断
                pageIndex = pageIndex < 1 ? 1 : pageIndex;
                pageSize = pageSize < 1 ? 12 : pageSize;

                //计算跳过数量
                int skip = (pageIndex - 1) * pageSize;

                return OperateResult<IQueryable<TModel>>.Succeeded(list.Skip(skip).Take(pageSize));
            }
            rowCount = 0;
            return OperateResult<IQueryable<TModel>>.Failed(result.Error);
        }

        public OperateResult<TModel> Model(Guid guid)
        {
            try
            {
                var model = Entities.Set<TModel>().Find(guid);
                return OperateResult<TModel>.Succeeded(model);
            }
            catch (Exception ex)
            {
                return OperateResult<TModel>.Failed(ex);
            }
        }

        public OperateResult<IQueryable<TModel>> Select()
        {
            try
            {
                var models = Entities.Set<TModel>();
                return OperateResult<IQueryable<TModel>>.Succeeded(models);
            }
            catch (Exception ex)
            {
                return OperateResult<IQueryable<TModel>>.Failed(ex);
            }
        }
    }
}